
local require = require
local setmetatable = setmetatable
local error = error
local table = table
local ngx = ngx
local bit = bit
local os = os
local string = string
local tonumber = tonumber
local server = require "modules.server"
local redis = require "redis"
local json = require 'cjson'
local util = require 'util'
local conf = require 'conf'
local pcall = pcall
local null = ngx.null
local unpack = unpack
local pairs = pairs
local math = math
local type = type
local protocal = require 'protocal'
local planeModel = require 'planeModel'
package.cpath = "/opt/xyitech/jieyan-backend-production/xbit/?.so"
local xbit = require 'xbit'

module(...)
_VERSION = '0.1'
 _int32_t = 0
 _int16_t = 1
 _float = 2
 _uint32_t = 4
 _uint16_t = 5
 _uint8_t = 6
 _int8_t = 7


local _fs = util.getChannel("fs_all")
local _ws = util.getChannel("ws_all")
local _fids = util.getChannel("fids")

local main_channel_name = "jieyan"
local verified = false
local secret = "Xunyi666"
local opts = {}
local sims = {}
local timer_end = false

local function update()
    -- ngx.log(ngx.ERR, json.encode(sims))
    for k,v in pairs(sims) do
        if v then
            v:update()
        end
    end
end

local function out(red_p)
    for k,v in pairs(sims) do
        if v then
            local res = v:out()
            for i,m in pairs(res) do
                -- ngx.log(ngx.ERR, json.encode(m))
                -- ngx.log(ngx.ERR, _ws)
                local r, err = red_p:publish(_ws, json.encode(m))
                -- ngx.log(ngx.ERR, r)
                -- ngx.log(ngx.ERR, err)
            end
        end
    end
end

function create(user, args)

    local wb, err = server:new{
      timeout = 5000,
      max_payload_len = 65535
    }

    local uid = util.get_uid()
    
    -- local moniter_fid = nil
    --create success
    if not wb then
      ngx.log(ngx.ERR, "failed to new websocket: ", err)
      return ngx.exit(444)
    end

    local red_set = redis:new()
    red_set:set_timeout(1000) -- 1 sec
    local ok, err = red_set:connect("127.0.0.1", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: ", err)
    end
    ngx.log(ngx.ERR, "redis connected")
    local warp = function (red_p)
        update()

        out(red_p)
    end
    local delay = 1
    local main
    main = function()
        if timer_end then
            ngx.exit(200)
            return
        end
         ngx.log(ngx.ERR, "every sec")
         local red_p= redis:new()
        red_p:set_timeout(1000) -- 1 sec
        local ok, err = red_p:connect("127.0.0.1", 6379)
        if not ok then
            ngx.log(ngx.ERR, "failed to connect redis: ", err)
        end
         warp(red_p)
         local ok, err = ngx.timer.at(delay, main)
         if not ok then
             ngx.log(ngx.ERR, "failed to create the timer: ", err)
             return
         end
    end

    main()
    ngx.log(ngx.ERR, "entering main loop")
    --main loop

    while true do
        -- 获取数据
        local data, typ, err = wb:recv_frame()
        ngx.log(ngx.ERR, data)
        ngx.log(ngx.ERR, typ)
        -- 如果连接损坏 退出
        if wb.fatal then
            ngx.log(ngx.ERR, "failed to receive frame: ", err)
            -- return ngx.exit(444)
            break
        end
     
        if not data then
            -- local bytes, err = wb:send_ping()
            -- if not bytes then
            --   ngx.log(ngx.ERR, "failed to send ping: ", err)
            --   -- return ngx.exit(444)
            --   break
            -- end
            -- ngx.log(ngx.ERR, "send ping: ", data)
        elseif typ == "close" then
            break
        elseif typ == "text" then
            data = handleData(data, red_p, red_set, wb, uid)
        end
    end

    ngx.log(ngx.ERR, "websocket closing")
    -- red_p:close()
    -- red_set:close()
    wb:send_close()
    timer_end = true
    -- ngx.thread.kill(co, false)
    ngx.exit(200)
end
--  _int32_t = 0
--  _int16_t = 1
--  _float = 2
--  _uint32_t = 4
--  _uint16_t = 5
--  _uint8_t = 6
--  _int8_t = 7

function handleData(data, red_p, red_set, wb, uid)
    -- if data == secret then
    --     verified = true
    -- end
    -- if not verified then
    --     return
    -- end
    
    ngx.log(ngx.ERR, data)
    local action, key, value, value1 = unpack(util.split(data, " "))
    ngx.log(ngx.ERR, action)
    ngx.log(ngx.ERR, key)
    if action == "set" then
        local ok, _value = pcall(json.decode, value)

        if ok and  (type(_value) == "table") then
            opts[key] = _value
        else
            opts[key] = value
        end
        wb:send_text("key: " .. key .. " set to " .. value)
    end
    if action == "get" then
        wb:send_text("key: " .. key .. " value is " ..  json.encode(opts[key]))
    end
    if action == "spawn" then
        if not opts.order_ids then
            wb:send_text("order_ids not set")
        end
        if not opts.fids then
            wb:send_text("fids not set")
        end

        if #opts.order_ids ~= #opts.fids then
            wb:send_text("order_ids length not equal to fids")
        end

        for i=1,#opts.order_ids do
            local orderId = opts.order_ids[i]
            local fid = opts.fids[i]
            local startAt = 1
            local model = planeModel:new({["orderId"] = orderId, ["fid"] = fid})
            table.insert(sims, model)
        end
        opts.order_ids = nil
        opts.fids = nil
        wb:send_text("spawn finish")
    end
end

function default(args)
    local user = nil
    if args.token then
        user = conf.parse_token(args, "order")
    end
    if args.action == 'create' then
        create(user, args)
    end
end
local class_mt = {
    __newindex = function (table, key, val)
        error('attempt to write to undeclared variable "' .. key .. '"')
    end
}
setmetatable(_M, class_mt)